﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Markup;

namespace Open.Infrastructure.Draggable
{
    public class XamlSymbolResourceDictSerializer : IDisposable, IXamlSymbolResourceDictSerializer
    {
        #region private fields

        private Stream xamlstream = null;

        private string _xmalRDHander = string.Empty;

        private string _xmalRDFooter = "</ResourceDictionary>";

        private string xamlText = string.Empty;

        private Stream xamlStreamCopy = null;

        StreamReader streamCopyReader = null;

        #endregion

        #region public fields and attributes

        private Dictionary<string, string> xamlSymbols = new Dictionary<string, string>();

        public Dictionary<string, string> XamlSymbols
        {
            get { return xamlSymbols; }
            set { xamlSymbols = value; }
        }

        public string XmalRDHander
        {
            get { return _xmalRDHander; }
            set { _xmalRDHander = value; }
        }

        public string XmalRDFooter
        {
            get { return _xmalRDFooter; }
            set { _xmalRDFooter = value; }
        }

        public Stream Xamlstream
        {
            get { return xamlstream; }
            set
            {
                xamlstream = value;
                xamlStreamCopy = new MemoryStream();
                xamlstream.CopyTo(xamlStreamCopy);
                xamlStreamCopy.Position = 0;
                xamlstream.Position = 0;
            }
        }

        #endregion

        #region contructor

        public XamlSymbolResourceDictSerializer(Stream xamlStream)
        {
            Xamlstream = xamlStream;
        }

        public XamlSymbolResourceDictSerializer() { }

        #endregion

        #region public function

        public ResourceDictionary Read()
        {
            InitializeXamlSymbols();
            xamlstream.Position = 0;
            return XamlReader.Load(xamlstream) as ResourceDictionary;
        }

        public string Save()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(_xmalRDHander);
            sb.AppendLine(serializeXamlSymbols());
            sb.AppendLine(_xmalRDFooter);
            return sb.ToString();
        }

        #endregion 

        #region private method

        private void InitializeXamlSymbols()
        {
            System.Xaml.XamlXmlReader reader = new System.Xaml.XamlXmlReader(xamlstream);
            int linenum = 0;
            int linepos = 0;
            initializeRDHander(reader);
            initializeSymbols(reader);
            //initializeRDFooter(reader, ref linenum, ref linepos);

            reader.Close();

        }

        private void initializeSymbols(System.Xaml.XamlXmlReader reader)
        {
            int beginlinenum = reader.LineNumber;
            int beginlinepos = reader.LinePosition - 2;
            int endlinenum = -1;
            int endlinepos = -1;
            string key = string.Empty;
            while (reader.Read())
            {

                if (reader.NodeType == System.Xaml.XamlNodeType.StartObject && reader.Type.Name.Contains("Symbol"))
                {
                    endlinenum = reader.LineNumber;
                    endlinepos = reader.LinePosition - 2;


                    int linenum = endlinenum - beginlinenum;
                    StringBuilder sb = new StringBuilder(linenum);

                    //int count=endIndex - beginIndex;
                    //char[] buffer = new char[count];
                    //streamreader.ReadBlock(buffer, beginIndex, count);
                    //xmalRDHander = new string(buffer);
                    //string firstline = streamCopyReader.ReadLine();
                    //sb.AppendLine(firstline);

                    for (int i = 0; i < linenum; i++)
                    {
                        string linestr = streamCopyReader.ReadLine();
                        sb.AppendLine(linestr);
                    }
                    //char[] buffer = new char[endlinepos + 1];
                    //string endline = streamCopyReader.ReadLine();
                    ////streamreader.ReadBlock(buffer, (int)streamreader.BaseStream.Position, buffer.Length);
                    //sb.AppendLine(endline);
                    string xamlsymbol = sb.ToString();
                    xamlSymbols.Add(key, xamlsymbol);
                    beginlinenum = reader.LineNumber;
                    beginlinepos = reader.LinePosition - 2;
                }



                if (reader.NodeType == System.Xaml.XamlNodeType.StartMember && reader.Member.Name.ToUpper() == "KEY")
                {
                    if (reader.LineNumber == beginlinenum)
                    {
                        while (reader.Read() && reader.NodeType != System.Xaml.XamlNodeType.Value) { }
                        key = reader.Value.ToString();
                    }
                }
            }
        }

        private void initializeRDHander(System.Xaml.XamlXmlReader reader)
        {
            //int beginIndex = (int)xamlstream.Position;
            int beginlinenum = reader.LineNumber;
            int beginlinepos = reader.LinePosition;
            int endlinenum = -1;
            int endlinepos = -1;
            //int endIndex = -99999;
            while (reader.Read())
            {
                if (reader.NodeType == System.Xaml.XamlNodeType.StartObject && reader.Type.Name.Contains("Symbol"))
                {
                    endlinenum = reader.LineNumber;
                    endlinepos = reader.LinePosition;
                    break;
                }
            }
            if (endlinenum > 0)
            {
                xamlStreamCopy.Position = 0;
                int linenum = endlinenum - beginlinenum;
                StringBuilder sb = new StringBuilder(linenum);
                streamCopyReader = new StreamReader(xamlStreamCopy);

                //int count=endIndex - beginIndex;
                //char[] buffer = new char[count];
                //streamreader.ReadBlock(buffer, beginIndex, count);
                //xmalRDHander = new string(buffer);
                for (int i = 0; i < linenum - 1; i++)
                {
                    string linestr = streamCopyReader.ReadLine();
                    sb.AppendLine(linestr);
                }
                //char[] buffer = new char[endlinepos + 1];
                //string endline = streamCopyReader.ReadLine();
                //streamreader.ReadBlock(buffer, (int)streamreader.BaseStream.Position, buffer.Length);
                //sb.AppendLine(endline.Substring(0, endlinepos -2));
                _xmalRDHander = sb.ToString();
                //xamlStreamCopy.Position = xamlStreamCopy.Position - endline.Length + 1;

            }

        }

        private string serializeXamlSymbols()
        {
            StringBuilder sb = new StringBuilder(xamlSymbols.Count);
            foreach (string xamlsymbol in xamlSymbols.Values)
            {
                sb.AppendLine(xamlsymbol);
            }
            return sb.ToString();
        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            xamlSymbols.Clear();
            xamlSymbols = null;
            if (xamlstream != null)
            {
                xamlstream.Dispose();
                xamlstream.Close();
            }
            if (xamlStreamCopy != null)
            {
                xamlStreamCopy.Dispose();
                xamlStreamCopy.Close();
            }
            if (streamCopyReader != null)
            {
                streamCopyReader.Dispose();
                streamCopyReader.Close();
            }
        }

        #endregion
    }
    public interface IXamlSymbolResourceDictSerializer
    {
        /// <summary>
        /// deserialize object from the xaml stream
        /// </summary>
        /// <returns>return the instance of class ResourceDictionary </returns>
        System.Windows.ResourceDictionary Read();
        /// <summary>
        /// serialize instance into xaml format
        /// </summary>
        /// <returns></returns>
        string Save();
        /// <summary>
        /// Get or set the stream of the xaml ,the root node of which is ResourceDictionary
        /// </summary>
        System.IO.Stream Xamlstream { get; set; }
        /// <summary>
        /// Get the dictionary of symbols in xaml format 
        /// </summary>
        Dictionary<string, string> XamlSymbols
        {
            get;
        }
        /// <summary>
        /// the footer of the serialize xaml document
        /// </summary>
        string XmalRDFooter { get; set; }
        /// <summary>
        /// the hander of the serialize xaml document
        /// </summary>
        string XmalRDHander { get; set; }
    }
}
